from flask_jwt_extended import (
    create_access_token,
    create_refresh_token,
    jwt_required,
    get_jwt_identity
)
from flask import jsonify, request
from flask_jwt_extended import create_refresh_token, get_jwt_identity
# from app.models import User, db
from app.models import *
from hashlib import md5
import hashlib
import time
from jwt import ExpiredSignatureError, InvalidTokenError
from jwt.exceptions import ExpiredSignatureError, DecodeError
import jwt
from flask import current_app
from jwt import ExpiredSignatureError, InvalidTokenError
from datetime import datetime, timedelta

 # 辅助函数
def get_device(device_id):
    # 使用 objects 查询
    return User.objects(deviceId=device_id, is_device=True).first()

def get_password(device_id):
    user = User.objects(deviceId=device_id).first()
    return user.password if user else None

def get_id_by_device_id(device_id):
    user = User.objects(deviceId=device_id).first()
    return str(user.id) if user else None  # MongoDB 的 ObjectId 需要转为字符串

def validate_required(data, required_fields):
    missing = [field for field in required_fields if field not in data]
    return len(missing) == 0, missing
# Ticket生成与验证
def generate_ticket(device_id):
    timestamp = int(time.time())
    expire_time = timestamp + Config.TICKET_EXPIRATION
    raw = f"{device_id}{timestamp}{Config.JWT_SECRET_KEY}"
    return hashlib.sha256(raw.encode()).hexdigest(), expire_time

def verify_signature(ticket, device_id, password, signature):
    server_sign = hashlib.md5(
        (ticket + device_id + password).encode('utf-8')
    ).hexdigest()
    return server_sign.lower() == signature.lower()


def register():
    data = request.json
    deviceId = data.get('deviceId')
    password = data.get('password')
    
    # 使用 MongoEngine 的 objects 查询
    if User.objects(deviceId=deviceId).first():
        return jsonify({"msg": "Username already exists"}), 201
        
    new_user = User(deviceId=deviceId, password=password)
    new_user.save()  # 替换 commit
    return jsonify({"msg": "User created successfully"}), 200


# 接口路由
def getTicket(deviceId):
     # 清空 refresh 计数器  
    current_app.redis_conn.delete(f"refresh_limit:{deviceId}") 
    # 这这这
    if deviceId is None or deviceId == "":
        return jsonify(
            code=201, 
            msg="缺少参数",
            ticket=None
        ), 200
    
    device = get_device(deviceId)
    if not device:
        return jsonify(
            code=202, 
            msg="未知设备ID",
            ticket=None
        ), 200
    
    ticket_value = generate_ticket(deviceId)
    
    # 存储Ticket到Redis
    try:
        # 存储Ticket到Redis（示例）
        current_app.redis_conn.setex(
            f"ticket:{ticket_value}", 
            Config.TICKET_EXPIRATION, 
            value=deviceId
        )
    except Exception as e:
        current_app.logger.critical(f"Redis错误: {str(e)}")
        return jsonify(
            code=500,
            msg="服务器内部错误,Redis错误",
            ticket=None
        ), 500
    
    return jsonify(
        code=200,
        msg ="成功",
        data={
            "ticket": f"{ticket_value}",
        }
    ), 200

def getToken():
    data = request.get_json()
    valid, missing = validate_required(data, ['deviceId', 'ticket', 'signature'])
    if not valid:
        return jsonify(code=201, msg=f"缺少参数: {missing}", data=None), 200
    
    device = data.get('deviceId')
    user = User.objects(deviceId=device).first()
    if not user:
        return jsonify(code=202, msg="未知设备ID", data=None), 200
    
    if not verify_signature(data['ticket'], device, user.password, data['signature']):
        return jsonify(code=203, msg="无效签名", data=None), 200
    
    expiry_time = datetime.utcnow() + timedelta(minutes=15)
    payload = {
        "deviceId": device,
        "exp": expiry_time  # JWT 自动识别 exp 字段为过期时间
    }
    
    token = jwt.encode(payload, user.password, algorithm="HS256")
    return jsonify(code=200, msg="成功", data={"token": token}), 200

def refreshtoken():
    data = request.get_json()
    if not data or 'deviceId' not in data or 'token' not in data or 'signature' not in data:
        return jsonify(code=201, msg="缺少参数", data=None), 200
    
    device = data.get('deviceId')
    user = User.objects(deviceId=device).first()
    if not user:
        return jsonify(code=202, msg="未知设备ID", data=None), 200
    
    if not verify_signature(data['token'], device, user.password, data['signature']):
        return jsonify(code=203, msg="无效签名", data=None), 200
    
    limit_key = f"refresh_limit:{device}"
    try:
            # 使用 Redis Pipeline 保证原子性操作
            pipe = current_app.redis_conn.pipeline()
            current_count = current_app.redis_conn.get(limit_key)
            if current_count is None:
                # 首次请求：设置计数器和过期时间（原子操作）
                pipe.setex(limit_key, 60, 1)
            else:
                # 后续请求：增加计数器
                pipe.incr(limit_key)
            # 执行所有命令
            pipe.execute()

            # 获取最新计数值
            current_count = int(current_app.redis_conn.get(limit_key) or 0)
            if current_count > 1:  # 允许每60秒最多1次刷新
                return jsonify(
                    code=429,  # 正确状态码 429 Too Many Requests
                    msg="刷新频率过高",
                    data=None
                ), 429

    except Exception as e:
            current_app.logger.error(f"Redis操作失败: {str(e)}")
            return jsonify(code=500, msg="服务器内部错误", data=None), 500

        # 生成新 Token（修复密钥问题）
    expiry_time = datetime.utcnow() + timedelta(minutes=15)
    payload = {
            "deviceId": device,
            "exp": expiry_time
        }
    token = jwt.encode(payload, current_app.config['SECRET_KEY'], algorithm="HS256")
    return jsonify(
            code=200,
            msg="刷新成功",
            data={"token": token}
        ), 200
    
    

